/*
 * Open LiveReplay Server - Live replay server for Supreme Commander
 * 
 * Copyright (C) 2009, 2009 Open LiveReplay Server Project
 * 
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * 
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details:
 * http://www.gnu.org/copyleft/lesser.html#TOC3
 */
package net.galacticwar.replayserver;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.galacticwar.lua.LittleEndianInputStream;
import net.galacticwar.lua.LuaDeserialize;
import net.galacticwar.lua.LuaException;
import net.galacticwar.lua.LuaPair;
import net.galacticwar.lua.LuaTable;

/**
 * 
 * This class contains all Replay information once the data has been parsed
 * 
 * @author Yoann Meste (aka Mancer)
 *
 */
public class Replay {

	private String supcomVersion;
	private String replayVersion;
	private LuaTable mod;
	private LuaTable scenario;
	private Map<String, Integer> names = new HashMap<String, Integer>();
	private boolean cheatsEnabled;
	private List<LuaTable> armies = new ArrayList<LuaTable>();
	private int randomSeed;
	
	public Replay() {
		
	}
	
	public void read(File file) throws IOException, UnknownReplayFormatException{
		FileInputStream fis = new FileInputStream(file);
		BufferedInputStream bis = new BufferedInputStream(fis);
		LittleEndianInputStream in = new LittleEndianInputStream(bis);
		
		read(in);
	}
	
	public void read(LittleEndianInputStream in) throws IOException, UnknownReplayFormatException{
		supcomVersion = in.readString();
		in.skip(3); //skipping the /r /n
		
		if (supcomVersion.startsWith("Supreme Commander v1") == false) {
			throw new UnknownReplayFormatException("The file format of this replay is unknonw");
		}
		
		replayVersion = in.readString();
		in.skip(3); //skipping the /r /n
		
		if (replayVersion.startsWith("Replay v1.9") == false) {
			throw new UnknownReplayFormatException("The file format of this replay is unknonw");
		}

		in.skip(1);
		
		try{
			@SuppressWarnings("unused")
			int count = in.readInt32();
			mod = (LuaTable)LuaDeserialize.parseLua(in);

			count = in.readInt32();
			scenario = (LuaTable)LuaDeserialize.parseLua(in);
			
			int numSource= in.read();
			for (int i = 0; i < numSource; i++) {
				String name = in.readString();
				int val = in.readInt32();
				names.put(name, val);
			}
			
			cheatsEnabled = in.read() != 0;
			
			int numArmies = in.read();
			
			for (int i = 0; i < numArmies; i++) {
				@SuppressWarnings("unused")
				int c = in.readInt32();
				LuaTable army = (LuaTable)LuaDeserialize.parseLua(in);
				armies.add(army);
				
				int b = in.read();
				byte[] data = new byte[1];

	            if(b != 255){
	            	in.read(data);
	            }
	                
			}
			
			randomSeed = in.readInt32();

		}
		catch (LuaException e) {
			throw new UnknownReplayFormatException("Impossible to parse this replay. Lua format unknown");
		}
		
		finally{
			in.close();
		}
		
	}
	
	public boolean isValid(){
		if (supcomVersion==null) {
			return false;
		}
		else{
			return supcomVersion.startsWith("Supreme Commander v1");
		}
		
	}
 	
	public String getVersion() {
		return supcomVersion;
	}
	
	public String getReplayVersion() {
		return replayVersion;
	}
	
	public String getMap() {
		if (scenario == null) {
			return "Replay not parsed yet";
		}
		Object o = scenario.getObject("name");
		if (o == null) {
			return "Unknown map";
		}
		
		return (String)o;
	}
	
	public boolean isCheatsEnabled() {
		return cheatsEnabled;
	}
	
	public List<String> getMods(){
		List<String> list = new ArrayList<String>();
		for (LuaPair pair : mod) {
			Object o = pair.getValue();
			if (o instanceof LuaTable) {
				LuaTable table = (LuaTable) o;
				list.add((String) table.getObject("name"));
			}
		}
		return list;
	}


	public List<Player> getPlayers(){
		List<Player> list = new ArrayList<Player>();
		for (LuaTable playerTable : armies) {
			if (playerTable.getObject("Human").equals(true)) {
				String name = (String)playerTable.getObject("PlayerName");
				Float faction = (Float)playerTable.getObject("Faction");
				Float team = (Float)playerTable.getObject("Team");
				Float color = (Float)playerTable.getObject("PlayerColor");
				
				Player player = new Player(name, faction, team, color);
				list.add(player);
			}
		}
		

		return list;
	}
	
	public int getRandomSeed() {
		return randomSeed;
	}
	
}
